home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1999 March
/
EnigmA AMIGA RUN 35 (1999)(G.R. Edizioni)(IT)[!][issue 1999-03].iso
/
earcd
/
devel
/
vbcc-src
/
machines
/
ppc
/
machine.c
next >
Wrap
C/C++ Source or Header
|
1999-01-01
|
71KB
|
1,927 lines
/* Code generator for a PPC RISC cpu with 32 general purpose, */
/* 32 floating point and 8 condition code registers. */
#include "supp.h"
static char FILE_[]=__FILE__;
/* Public data that MUST be there. */
/* Name and copyright. */
char cg_copyright[]="vbcc code-generator for PPC V0.3 (c) in 1997-99 by Volker Barthelmann";
/* Commandline-flags the code-generator accepts */
int g_flags[MAXGF]={STRINGFLAG,STRINGFLAG,0,0,0,0,
0,0,0,0,0,
0,0,0};
char *g_flags_name[MAXGF]={"cpu","fpu","const-in-data","sd","merge-constants","fsub-zero",
"elf","amiga-align","no-regnames","peephole","setccs",
"use-lmw","poweropen","sc"};
union ppi g_flags_val[MAXGF];
/* Alignment-requirements for all types in bytes. */
zlong align[16];
/* Alignment that is sufficient for every object. */
zlong maxalign;
/* CHAR_BIT for the target machine. */
zlong char_bit;
/* Tabelle fuer die Groesse der einzelnen Typen */
zlong sizetab[16];
/* Minimum and Maximum values each type can have. */
/* Must be initialized in init_cg(). */
zlong t_min[32];
zulong t_max[32];
/* Names of all registers. */
char *regnames[MAXR+1]={"noreg",
"r0","r1","r2","r10","r9","r8","r7","r6",
"r5","r4","r3","r11","r12","r13","r31","r30",
"r29","r28","r27","r26","r25","r24","r23","r22",
"r21","r20","r19","r18","r17","r16","r15","r14",
"f9","f10","f0","f11","f12","f13","f8","f7",
"f6","f5","f4","f3","f2","f1","f14","f15",
"f16","f17","f18","f19","f20","f21","f22","f23",
"f24","f25","f26","f27","f28","f29","f30","f31",
"cr0","cr1","cr2","cr3","cr4","cr5","cr6","cr7",
"cnt"};
/* The Size of each register in bytes. */
zlong regsize[MAXR+1];
/* Type which can store each register. */
struct Typ *regtype[MAXR+1];
/* regsa[reg]!=0 if a certain register is allocated and should */
/* not be used by the compiler pass. */
int regsa[MAXR+1];
/* Specifies which registers may be scratched by functions. */
int regscratch[MAXR+1]={0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,0,0,0,1,1,1,1};
struct reg_handle empty_reg_handle={0,0};
/* Names of target-specific variable attributes. */
char *g_attr_name[]={"__far","__near","__chip","__saveds",0};
/****************************************/
/* Private data and functions. */
/****************************************/
static char *mregnames[MAXR+1];
static long malign[16]= {1,1,2,4,4,4,4,1,4,1,1,1,4,1};
static long msizetab[16]={1,1,2,4,4,4,8,0,4,0,0,0,4,0};
static struct Typ ltyp={LONG},ldbl={DOUBLE},lchar={CHAR};
static int r0=1; /* special register */
static int r2=3; /* reserved or toc */
static int r3=11; /* return value */
static int sp=2; /* Stackpointer */
static int fp=2; /* Framepointer */
static int sd=14; /* SmallDataPointer */
static int t1=12,t2=13,t3=1; /* Temporaries used by code generator */
static int f1=33,f2=34,f3=35; /* Temporaries used by code generator */
static int cr0=65; /* Default condition-code-register */
#define DATA 0
#define BSS 1
#define CODE 2
#define RODATA 3
#define TOC 4
static int lastlabel;
static int section=-1,newobj,crsave;
static char *codename="\t.text\n",*dataname="\t.data\n",*bssname="",
*rodataname="\t.section\t.rodata\n",*tocname="\t.tocd\n";
static int is_const(struct Typ *);
static char *labprefix="l",*idprefix="_",*tocprefix="@_";
static long frameoffset,pushed,maxpushed,framesize,localoffset,minframe=8;
static void probj2(FILE *f,struct obj *p,int t);
struct StatFPtrList {
struct StatFPtrList *next;
struct Var *vptr;
};
static struct StatFPtrList *firstfptr = NULL;
static long real_offset(struct obj *o)
{
long off;
if(zl2l(o->v->offset)>=0){
return zl2l(o->v->offset)+frameoffset+zl2l(o->val.vlong);
}else{
return framesize+minframe-zl2l(o->v->offset)-zl2l(maxalign)+zl2l(o->val.vlong);
}
}
static long hi(long off)
{
zlong zl=l2zl(off),r=zlrshift(zl,l2zl(16L));
if(!zleqto(zland(zl,l2zl(32768L)),l2zl(0L))) r=zladd(r,l2zl(1L));
return zl2l(zs2zl(zl2zs(zland(r,l2zl(65535L)))));
}
static long lo(long off)
{
return zl2l(zs2zl(zl2zs(zland(l2zl(off),l2zl(65535L)))));
}
static struct fpconstlist {
struct fpconstlist *next;
int label,typ;
union atyps val;
} *firstfpc;
static int addfpconst(struct obj *o,int t)
{
struct fpconstlist *p=firstfpc;
t&=NQ;
if(g_flags[4]&USEDFLAG){
for(p=firstfpc;p;p=p->next){
if(t==p->typ){
eval_const(&p->val,t);
if(t==FLOAT&&zdeqto(vdouble,zf2zd(o->val.vfloat))) return p->label;
if(t==DOUBLE&&zdeqto(vdouble,o->val.vdouble)) return p->label;
}
}
}
p=mymalloc(sizeof(struct fpconstlist));
p->next=firstfpc;
p->label=++label;
p->typ=t;
p->val=o->val;
firstfpc=p;
return p->label;
}
#define REG_IND 1
#define IMM_IND 2
#define UPDATE 64
static struct obj *cam(int flags,int base,long offset)
/* Initializes an addressing-mode structure and returns a pointer to */
/* that object. Will not survive a second call! */
{
static struct obj obj;
static struct AddressingMode am;
obj.am=&am;
am.flags=flags;
am.base=base;
am.offset=offset;
return &obj;
}
static char *ldt[]={"","bz","ha","wz","wz","fs","fd","","wz","","","","","","","",
"","bz","hz","wz","wz"};
static char *sdt[]={"","b","h","w","w","fs","fd","","w","","","","","","","",
"","b","h","w","w"};
static int use_sd(int t)
/* Shall the object of type t be addressed in small-data-mode? */
{
if(g_flags[3]&USEDFLAG) return 1;
if((g_flags[13]&USEDFLAG)&&(t&NQ)<=POINTER) return 1;
return 0;
}
static void load_address(FILE *f,int r,struct obj *o,int typ)
/* Generates code to load the address of a variable into register r. */
{
if(!(o->flags&VAR)) ierror(0);
if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER){
long off=real_offset(o);
if(off<=32767){
fprintf(f,"\taddi\t%s,%s,%ld\n",mregnames[r],mregnames[sp],off);
}else{
fprintf(f,"\taddis\t%s,%s,%ld\n",mregnames[r],mregnames[sp],hi(off));
fprintf(f,"\taddi\t%s,%s,%ld\n",mregnames[r],mregnames[r],lo(off));
}
}else{
if(use_sd(o->v->vtyp->flags)&&!(o->v->tattr&1)){
fprintf(f,"\tla\t%s,",mregnames[r]);
probj2(f,o,typ);fprintf(f,"(%s)\n",mregnames[sd]);
}else{
if(g_flags[12]&USEDFLAG){
zlong offset=o->val.vlong;
if((o->v->vtyp->flags&NQ)==FUNKT&&o->v->storage_class==STATIC){
/* check if static function pointer was already created in TOC */
struct StatFPtrList **oldsfp=&firstfptr;
struct StatFPtrList *sfp=firstfptr;
while(sfp){
if(sfp->vptr==o->v) break;
oldsfp=&sfp->next;
sfp=sfp->next;
}
if(!sfp){
/* create new function pointer variable "@__fname" in TOC */
*oldsfp=sfp=mymalloc(sizeof(struct StatFPtrList));
sfp->next=NULL;
sfp->vptr=o->v;
fprintf(f,"%s\t.align\t2\n%s%s%s:\n\t.long\t%s%s\n%s",
tocname,tocprefix,idprefix,o->v->identifier,
idprefix,o->v->identifier,codename);
}
}
fprintf(f,"\tl%s\t%s,%s",ldt[LONG],mregnames[r],tocprefix);
o->val.vlong=l2zl(0L);probj2(f,o,POINTER);o->val.vlong=offset;
fprintf(f,"(%s)\n",mregnames[r2]);
if(hi(zl2l(offset))) fprintf(f,"\taddis\t%s,%s,%ld\n",mregnames[r],mregnames[r],hi(zl2l(offset)));
if(lo(zl2l(offset))) fprintf(f,"\taddi\t%s,%s,%ld\n",mregnames[r],mregnames[r],lo(zl2l(offset)));
}else{
fprintf(f,"\tlis\t%s,",mregnames[r]);
probj2(f,o,typ);fprintf(f,"@ha\n");
fprintf(f,"\taddi\t%s,%s,",mregnames[r],mregnames[r]);
probj2(f,o,typ);fprintf(f,"@l\n");
}
}
}
}
static void load_reg(FILE *f,int r,struct obj *o,int typ,int tmp)
/* Generates code to load a memory object into register r. tmp is a */
/* general purpose register which may be used. tmp can be r. */
{
typ&=NU;
if(o->flags&KONST){
long l;
eval_const(&o->val,typ);
if(typ==FLOAT||typ==DOUBLE){
int lab;
if((g_flags[5]&USEDFLAG)&&zdeqto(vdouble,d2zd(0.0))){
fprintf(f,"\tfsub\t%s,%s,%s\n",mregnames[r],mregnames[r],mregnames[r]);
return;
}
lab=addfpconst(o,typ);
if(use_sd(typ)){
fprintf(f,"\tl%s\t%s,%s%d(%s)\n",ldt[typ],mregnames[r],labprefix,lab,mregnames[sd]);
}else{
if(g_flags[12]&USEDFLAG){
fprintf(f,"\tl%s\t%s,%s%s%ld(%s)\n",ldt[LONG],mregnames[tmp],tocprefix,labprefix,(long)lab,mregnames[r2]);
fprintf(f,"\tl%s\t%s,0(%s)\n",ldt[typ],mregnames[r],mregnames[tmp]);
}else{
fprintf(f,"\tlis\t%s,%s%d@ha\n",mregnames[tmp],labprefix,lab);
fprintf(f,"\tl%s\t%s,%s%d@l(%s)\n",ldt[typ],mregnames[r],labprefix,lab,mregnames[tmp]);
}
}
return;
}
l=hi(zl2l(vlong));
if(l){
fprintf(f,"\tlis\t%s,%ld\n",mregnames[r],l);
l=lo(zl2l(vlong));
if(l) fprintf(f,"\taddi\t%s,%s,%ld\n",mregnames[r],mregnames[r],l);
}else{
fprintf(f,"\tli\t%s,%ld\n",mregnames[r],zl2l(vlong));
}
return;
}
if((o->flags&VAR)&&(o->v->storage_class==EXTERN||o->v->storage_class==STATIC)){
if(o->flags&VARADR){
load_address(f,r,o,POINTER);
}else{
if(use_sd(o->v->vtyp->flags)&&!(o->v->tattr&1)){
fprintf(f,"\tl%s\t%s,",ldt[typ],mregnames[r]);
probj2(f,o,typ);fprintf(f,"(%s)\n",mregnames[sd]);
}else{
if(g_flags[12]&USEDFLAG){
zlong offset=o->val.vlong;
fprintf(f,"\tl%s\t%s,%s",ldt[LONG],mregnames[tmp],tocprefix);
o->val.vlong=l2zl(0L);probj2(f,o,POINTER);o->val.vlong=offset;
fprintf(f,"(%s)\n",mregnames[r2]);
if(hi(zl2l(offset))) fprintf(f,"\taddis\t%s,%s,%ld\n",mregnames[tmp],mregnames[tmp],hi(zl2l(offset)));
fprintf(f,"\tl%s\t%s,%ld(%s)\n",ldt[typ],mregnames[r],lo(zl2l(offset)),mregnames[tmp]);
}else{
fprintf(f,"\tlis\t%s,",mregnames[tmp]);
probj2(f,o,typ);fprintf(f,"@ha\n");
fprintf(f,"\tl%s\t%s,",ldt[typ],mregnames[r]);
probj2(f,o,typ);fprintf(f,"@l(%s)\n",mregnames[tmp]);
}
}
}
}else{
if((o->flags&(DREFOBJ|REG))==REG){
if(r!=o->reg)
fprintf(f,"\t%smr\t%s,%s\n",r>=33?"f":"",mregnames[r],mregnames[o->reg]);
}else if(!o->am){
long off=real_offset(o);
if(off<=32767){
fprintf(f,"\tl%s\t%s,%ld(%s)\n",ldt[typ],mregnames[r],off,mregnames[sp]);
}else{
fprintf(f,"\taddis\t%s,%s,%ld\n",mregnames[r],mregnames[sp],hi(off));
fprintf(f,"\tl%s\t%s,%ld(%s)\n",ldt[typ],mregnames[r],lo(zl2l(off)),mregnames[r]);
}
}else{
fprintf(f,"\tl%s%s%s\t%s,",ldt[typ],(o->am->flags&UPDATE)?"u":"",(o->am->flags®_IND)?"x":"",mregnames[r]);
probj2(f,o,typ);fprintf(f,"\n");
}
}
if(typ==CHAR) fprintf(f,"\textsb\t%s,%s\n",mregnames[r],mregnames[r]);
}
static void store_reg(FILE *f,int r,struct obj *o,int typ)
/* Generates code to store register r into memory object o. */
{
int tmp;
typ&=NQ;
if((o->flags&VAR)&&(o->v->storage_class==EXTERN||o->v->storage_class==STATIC)){
int tmp=t1;
if(tmp==r) tmp=t2;
if(use_sd(o->v->vtyp->flags)&&!(o->v->tattr&1)){
fprintf(f,"\tst%s\t%s,",sdt[typ],mregnames[r]);
probj2(f,o,typ);fprintf(f,"(%s)\n",mregnames[sd]);
return;
}else{
if(g_flags[12]&USEDFLAG){
zlong offset=o->val.vlong;
fprintf(f,"\tl%s\t%s,%s",ldt[LONG],mregnames[tmp],tocprefix);
o->val.vlong=l2zl(0L);probj2(f,o,POINTER);o->val.vlong=offset;
fprintf(f,"(%s)\n",mregnames[r2]);
if(hi(zl2l(offset))) fprintf(f,"\taddis\t%s,%s,%ld\n",mregnames[tmp],mregnames[tmp],hi(zl2l(offset)));
fprintf(f,"\tst%s\t%s,%ld(%s)\n",sdt[typ],mregnames[r],lo(zl2l(offset)),mregnames[tmp]);
return;
}else{
fprintf(f,"\tlis\t%s,",mregnames[tmp]);
probj2(f,o,typ);fprintf(f,"@ha\n");
fprintf(f,"\tst%s\t%s,",sdt[typ],mregnames[r]);
probj2(f,o,typ);fprintf(f,"@l(%s)\n",mregnames[tmp]);
return;
}
}
}
if(!(o->flags&DREFOBJ)&&!o->am){
long off=real_offset(o);
if(r==t1) tmp=t2; else tmp=t1;
if(off<=32767){
fprintf(f,"\tst%s\t%s,%ld(%s)\n",sdt[typ],mregnames[r],off,mregnames[sp]);
}else{
fprintf(f,"\taddis\t%s,%s,%ld\n",mregnames[tmp],mregnames[sp],hi(off));
fprintf(f,"\tst%s\t%s,%ld(%s)\n",sdt[typ],mregnames[r],lo(off),mregnames[tmp]);
}
}else{
if(!o->am){
fprintf(f,"\tst%s\t%s,",sdt[typ],mregnames[r]);
probj2(f,o,typ);fprintf(f,"\n");
}else{
fprintf(f,"\tst%s%s%s\t%s,",sdt[typ],(o->am->flags&UPDATE)?"u":"",(o->am->flags®_IND)?"x":"",mregnames[r]);
probj2(f,o,typ);fprintf(f,"\n");
}
}
}
static long pof2(zulong x)
/* Yields log2(x)+1 oder 0. */
{
zulong p;int ln=1;
p=ul2zul(1L);
while(ln<=32&&zulleq(p,x)){
if(zuleqto(x,p)) return ln;
ln++;p=zuladd(p,p);
}
return 0;
}
static char *dct[]={"","byte","uahalf","uaword","uaword","uaword","uaword"};
static struct IC *do_refs(FILE *,struct IC *);
static void pr(FILE *,struct IC *);
static void function_top(FILE *,struct Var *,long);
static void function_bottom(FILE *f,struct Var *,long);
#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
static int q1reg,q2reg,zreg;
static char *ccs[]={"eq","ne","lt","ge","le","gt",""};
static char *logicals[]={"or","xor","and"};
static char *record[]={"","."};
static char *arithmetics[]={"slw","srw","add","sub","mullw","divw","mod"};
static char *isimm[]={"","i"};
static struct IC *do_refs(FILE *f,struct IC *p)
/* Does some pre-processing like fetching operands from memory to */
/* registers etc. */
{
int typ=p->typf,typ1,reg,c=abs(p->code);
if(c==CONVCHAR) typ=CHAR;
if(c==CONVUCHAR) typ=UNSIGNED|CHAR;
if(c==CONVSHORT) typ=SHORT;
if(c==CONVUSHORT) typ=UNSIGNED|SHORT;
if(c==CONVINT) typ=LONG;
if(c==CONVUINT) typ=UNSIGNED|LONG;
if(c==CONVLONG) typ=LONG;
if(c==CONVULONG) typ=UNSIGNED|LONG;
if(c==CONVFLOAT) typ=FLOAT;
if(c==CONVDOUBLE) typ=DOUBLE;
if(c==CONVPOINTER) typ=UNSIGNED|LONG;
if((typ&NQ)==POINTER) typ=UNSIGNED|LONG;
if((c==SUB||c==SUBIFP)&&(p->q2.flags&(KONST|DREFOBJ))==KONST&&(typ&NQ)<=LONG){
eval_const(&p->q2.val,typ);
if(zlleq(vlong,l2zl(32768L))&&zlleq(l2zl(-32767L),vlong)){
union atyps val;
if(c==SUB){
if(p->code==SUB) p->code=c=ADD; else p->code=c=-ADD;
}else{
if(p->code==SUBIFP) p->code=c=ADDI2P; else p->code=c=-ADDI2P;
}
c=abs(c);
val.vlong=zlsub(l2zl(0L),vlong);
eval_const(&val,LONG);
insert_const2(&p->q2.val,typ);
p->typf=typ=(typ&~UNSIGNED);
}
}
q1reg=q2reg=zreg=0;
if(p->q1.flags®) q1reg=p->q1.reg;
if(p->q2.flags®) q2reg=p->q2.reg;
if((p->z.flags&(REG|DREFOBJ))==REG) zreg=p->z.reg;
if((p->q1.flags&(KONST|DREFOBJ))==KONST){
eval_const(&p->q1.val,typ);
if((typ&NQ)==FLOAT||(typ&NQ)==DOUBLE) reg=f1; else reg=t1;
if(c==ASSIGN&&zreg) reg=zreg;
if(c==SETRETURN&&p->z.reg) reg=p->z.reg;
if(c!=SUB||(typ&NQ)>LONG||!zlleq(vlong,l2zl(32767L))||!zlleq(l2zl(-32768L),vlong)){
load_reg(f,reg,&p->q1,typ,t1);
q1reg=reg;
}
}else if(c!=ADDRESS){
if((typ&NQ)==FLOAT||(typ&NQ)==DOUBLE) reg=f1; else reg=t1;
if((c==ASSIGN||(c>=CONVCHAR&&c<=CONVULONG&&c!=CONVFLOAT&&c!=CONVDOUBLE))&&zreg>=1&&zreg<=32) reg=zreg;
if(c==SETRETURN&&p->z.reg) reg=p->z.reg;
if(p->q1.am){
load_reg(f,reg,&p->q1,typ,t1);
q1reg=reg;
}else{
if(p->q1.flags&&!q1reg){
if(p->q1.flags&DREFOBJ) {typ1=POINTER;reg=t1;} else typ1=typ;
if((typ1&NQ)<=POINTER){
int m=p->q1.flags;
p->q1.flags&=~DREFOBJ;
load_reg(f,reg,&p->q1,typ1,t1);
p->q1.flags=m;
q1reg=reg;
}
}
if((p->q1.flags&DREFOBJ)&&(typ&NQ)<=POINTER){
if((typ&NQ)==FLOAT||(typ&NQ)==DOUBLE) reg=f1; else reg=t1;
if((c==ASSIGN||(c>=CONVCHAR&&c<=CONVULONG&&c!=CONVFLOAT&&c!=CONVDOUBLE))&&zreg>=1&&zreg<=32) reg=zreg;
if(c==SETRETURN&&p->z.reg) reg=p->z.reg;
if(p->q1.am)
load_reg(f,reg,&p->q1,typ,t1);
else
load_reg(f,reg,cam(IMM_IND,q1reg,0),typ,t1);
q1reg=reg;
}
}
}
typ=p->typf;
if((p->q2.flags&(KONST|DREFOBJ))==KONST){
eval_const(&p->q2.val,typ);
if((typ&NQ)==FLOAT||(typ&NQ)==DOUBLE) reg=f2; else reg=t2;
if((typ&NQ)==FLOAT||(typ&NQ)==DOUBLE||c==DIV||c==SUB||c==MOD){
load_reg(f,reg,&p->q2,typ,t2);
q2reg=reg;
}else{
if((c>=OR&&c<=AND)||(c==COMPARE&&(typ&UNSIGNED))){
if(!zulleq(vulong,ul2zul(65535UL))){
load_reg(f,reg,&p->q2,typ,t2);
q2reg=reg;
}
}else{
if(!zlleq(vlong,l2zl(32767L))||!zlleq(l2zl(-32768L),vlong)){
load_reg(f,reg,&p->q2,typ,t2);
q2reg=reg;
}
}
}
}else{
if(p->q2.am){
if((typ&NQ)==FLOAT||(typ&NQ)==DOUBLE) reg=f2; else reg=t2;
load_reg(f,reg,&p->q2,typ,t2);
q2reg=reg;
}else{
if(p->q2.flags&&!q2reg){
if((p->q2.flags&DREFOBJ)) typ1=POINTER; else typ1=typ;
if((typ1&NQ)==FLOAT||(typ1&NQ)==DOUBLE) reg=f2; else reg=t2;
if((typ1&NQ)<=POINTER){
int m=p->q2.flags;
p->q2.flags&=~DREFOBJ;
load_reg(f,reg,&p->q2,typ1,t2);
p->q2.flags=m;
q2reg=reg;
}
}
if((p->q2.flags&DREFOBJ)&&(typ&NQ)<=POINTER){
if((typ&NQ)==FLOAT||(typ&NQ)==DOUBLE) reg=f2; else reg=t2;
if(p->q2.am)
load_reg(f,reg,&p->q2,typ,t2);
else
load_reg(f,reg,cam(IMM_IND,q2reg,0),typ,t2);
q2reg=reg;
}
}
}
if(p->z.am||(p->z.flags&&!isreg(z))){
typ=p->typf;
if((typ&NQ)==FLOAT||(typ&NQ)==DOUBLE) zreg=f3; else zreg=t3;
}
if(q1reg){ p->q1.flags=REG; p->q1.reg=q1reg;p->q1.am=0;}
if(q2reg){ p->q2.flags=REG; p->q2.reg=q2reg;p->q2.am=0;}
return p;
}
static void pr(FILE *f,struct IC *p)
/* Writes the destination register to the real destination if necessary. */
{
int typ=p->typf;
if(p->code==ADDRESS) typ=POINTER;
if(p->z.flags){
if(p->z.am){
store_reg(f,zreg,&p->z,typ);
}else if(!isreg(z)){
if(p->z.flags&DREFOBJ){
if(p->z.flags®){
if(p->z.am)
store_reg(f,zreg,&p->z,typ);
else
store_reg(f,zreg,cam(IMM_IND,p->z.reg,0),typ);
}else{
int r;
if(t1==zreg) r=t2; else r=t1;
load_reg(f,r,&p->z,POINTER,r);
store_reg(f,zreg,cam(IMM_IND,r,0),typ);
}
}else{
store_reg(f,zreg,&p->z,typ);
}
}else{
if(p->z.reg!=zreg)
fprintf(f,"\t%smr\t%s,%s\n",zreg>=33?"f":"",mregnames[p->z.reg],mregnames[zreg]);
}
}
}
static void probj2(FILE *f,struct obj *p,int t)
/* Prints an object. */
{
if(p->am){
if(p->am->flags®_IND) fprintf(f,"%s,%s",mregnames[p->am->offset],mregnames[p->am->base]);
if(p->am->flags&IMM_IND) fprintf(f,"%ld(%s)",p->am->offset,mregnames[p->am->base]);
return;
}
/* if(p->flags&DREFOBJ) fprintf(f,"(");*/
if(p->flags&VAR) {
if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER){
if(p->flags®){
fprintf(f,"%s",mregnames[p->reg]);
}else{
fprintf(f,"%ld(%s)",real_offset(p),mregnames[sp]);
}
}else{
if(!zleqto(l2zl(0L),p->val.vlong)){printval(f,&p->val,LONG,0);fprintf(f,"+");}
if(p->v->storage_class==STATIC&&(p->v->vtyp->flags&NQ)!=FUNKT){
fprintf(f,"%s%ld",labprefix,zl2l(p->v->offset));
}else{
fprintf(f,"%s%s",idprefix,p->v->identifier);
}
}
}
if((p->flags®)&&!(p->flags&VAR)) fprintf(f,"%s",mregnames[p->reg]);
if(p->flags&KONST){
printval(f,&p->val,t&NU,0);
}
/* if(p->flags&DREFOBJ) fprintf(f,")");*/
}
static int exists_freereg(struct IC *p,int reg)
/* Test if there is a sequence of FREEREGs containing FREEREG reg. */
{
while(p&&(p->code==FREEREG||p->code==ALLOCREG)){
if(p->code==FREEREG&&p->q1.reg==reg) return 1;
p=p->next;
}
return 0;
}
static size_t lsize;
static unsigned char *once,*twice;
static void peephole(struct IC *p)
/* Try to use addressing modes */
{
int c,c2,r,cnt;struct IC *p2;struct AddressingMode *am;
lsize=((label-lastlabel+1+7)/CHAR_BIT)*CHAR_BIT;
once=mymalloc(lsize);
twice=mymalloc(lsize);
memset(once,0,lsize);
memset(twice,0,lsize);
for(;p;p=p->next){
c=p->code;
/* Test which labels are jumped to more than once. */
if(c>=BEQ&&c<=BRA){
if(BTST(once,p->typf-lastlabel))
BSET(twice,p->typf-lastlabel);
else
BSET(once,p->typf-lastlabel);
}
/* Try test-opt */
if(c==TEST&&!(p->q1.flags&DREFOBJ)){
for(p2=p->prev;p2;p2=p2->prev){
c2=p2->code;
if(c2==NOP||c2==ALLOCREG||c2==FREEREG) continue;
if(c2==CALL||(c2>=LABEL&&c2<=BRA)) break;
if((p2->z.flags&DREFOBJ)&&(p->q1.flags&(REG|DREFOBJ))!=REG) break;
if(p->q1.flags==p2->z.flags&&p->q1.am==p2->z.am){
if(!(p->q1.flags&VAR)||(p->q1.v==p2->z.v&&zleqto(p->q1.val.vlong,p2->z.val.vlong))){
if(!(p->q1.flags®)||p->q1.reg==p2->z.reg){
if(p->z.flags==0||(isreg(z)&&p->z.reg==cr0)){
if(p->typf==p2->typf&&(!(p->typf&UNSIGNED)||!multiple_ccs)){
p2->code=-p2->code; /* mark it */
}
break;
}
}
}
}
}
}
/* Try update */
if((c==ADDI2P||c==SUBIFP)&&isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg){
if((p->q2.flags&(KONST|DREFOBJ))==KONST){
eval_const(&p->q2.val,p->typf);
if(c==SUBIFP) vlong=zlsub(l2zl(0L),vlong);
if(zlleq(l2zl(-32768L),vlong)&&zlleq(vlong,l2zl(32767L))){
struct obj *o;
r=p->q1.reg;cnt=0;o=0;
for(p2=p->next;p2;p2=p2->next){
c2=p2->code;
if(c2==NOP||c2==ALLOCREG||c2==FREEREG) continue;
if((c2==CALL&®scratch[r])||(c2>=LABEL&&c2<=BRA)) break;
if((p2->q1.flags&(DREFOBJ|REG))==REG&&p2->q1.reg==r) break;
if((p2->q2.flags&(DREFOBJ|REG))==REG&&p2->q2.reg==r) break;
if((p2->z.flags&(DREFOBJ|REG))==REG&&p2->z.reg==r) break;
if((p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){o=&p2->q1;cnt++;}
if((p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){o=&p2->q2;cnt++;}
if((p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){o=&p2->z;cnt++;}
if(cnt>1) break;
if(cnt==1){
if(p2->code==ASSIGN&&((p2->typf&NQ)>POINTER||!zleqto(p2->q2.val.vlong,sizetab[p2->typf&NQ])))
break;
o->am=am=mymalloc(sizeof(*am));
o->am->flags=(IMM_IND|UPDATE);
o->am->base=r;
o->am->offset=zl2l(vlong);
p->code=NOP;
break;
}
}
}
}
}
/* Try const(reg) */
if((c==ADDI2P||c==SUBIFP)&&(p->q2.flags&(KONST|DREFOBJ))==KONST&&isreg(z)){
int base;zlong of;
p2=p->next;
while(p2&&(p2->code==FREEREG||p2->code==ALLOCREG)) p2=p2->next;
if(p2) c2=p2->code; else c2=0;
eval_const(&p->q2.val,p->typf);
if(c==SUBIFP) of=zlsub(l2zl(0L),vlong); else of=vlong;
r=p->z.reg;
if(isreg(q1)) base=p->q1.reg; else base=r;
if(c2&&zlleq(l2zl(-32768L),of)&&zlleq(of,l2zl(32767L))&&c2!=CALL&&(c2<LABEL||c2>BRA)
&&(c2!=ASSIGN||((p2->typf&NQ)<=POINTER&&zleqto(p2->q2.val.vlong,sizetab[p2->typf&NQ])))
&&c2!=ADDRESS&&(((p2->z.flags&(DREFOBJ|REG))==REG&&p2->z.reg==r&&p2->q2.flags==0)||exists_freereg(p2->next,r))){
if(((p2->q1.flags&(REG|DREFOBJ))!=REG||p2->q1.reg!=r)
&&((p2->q2.flags&(REG|DREFOBJ))!=REG||p2->q2.reg!=r)){
cnt=0;
if((p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
p2->q1.am=am=mymalloc(sizeof(*am));
p2->q1.am->flags=IMM_IND;
p2->q1.am->base=base;
p2->q1.am->offset=zl2l(of);
cnt++;
}
if((p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
p2->q2.am=am=mymalloc(sizeof(*am));
p2->q2.am->flags=IMM_IND;
p2->q2.am->base=base;
p2->q2.am->offset=zl2l(of);
cnt++;
}
if((p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
p2->z.am=am=mymalloc(sizeof(*am));
p2->z.am->flags=IMM_IND;
p2->z.am->base=base;
p2->z.am->offset=zl2l(of);
cnt++;
}
if(isreg(q1)){
p->code=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
}else{
p->code=ASSIGN;p->q2.flags=0;
}
if(cnt==1&&((p2->q1.flags&(DREFOBJ|REG))!=REG||p2->q1.reg!=base)
&&((p2->q2.flags&(DREFOBJ|REG))!=REG||p2->q2.reg!=base)
&&((p2->z.flags&(DREFOBJ|REG))!=REG||p2->z.reg!=base) ){
/* Can we use update? */
p2=p2->next;
while(p2&&(p2->code==FREEREG||p2->code==ALLOCREG)) p2=p2->next;
if(p2){
c2=p2->code;
if(c2==ADDI2P||c2==SUBIFP){
if((p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==base
&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==base
&&(p2->q2.flags&(KONST|DREFOBJ))==KONST ){
eval_const(&p2->q2.val,p2->typf);
if(c2==SUBIFP) vlong=zlsub(l2zl(0L),vlong);
if(zleqto(vlong,of)){
am->flags|=UPDATE;
p2->code=NOP;
}
}
}
}
}
continue;
}
}
}
/* Try reg,reg */
if(c==ADDI2P&&isreg(q2)&&isreg(z)&&p->q2.reg!=p->z.reg){
int base,idx;
p2=p->next;
while(p2&&(p2->code==FREEREG||p2->code==ALLOCREG)) p2=p2->next;
if(p2) c2=p2->code; else c2=0;
r=p->z.reg;idx=p->q2.reg;
if(isreg(q1)) base=p->q1.reg; else base=r;
if(c2&&c2!=CALL&&(c2<LABEL||c2>BRA)
&&(c2!=ASSIGN||((p2->typf&NQ)<=POINTER&&zleqto(p2->q2.val.vlong,sizetab[p2->typf&NQ])))
&&c2!=ADDRESS&&exists_freereg(p2->next,r)){
if(((p2->q1.flags&(REG|DREFOBJ))!=REG||p2->q1.reg!=r)
&&((p2->q2.flags&(REG|DREFOBJ))!=REG||p2->q2.reg!=r) ){
cnt=0;
if((p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
p2->q1.am=am=mymalloc(sizeof(*am));
p2->q1.am->flags=REG_IND;
p2->q1.am->base=base;
p2->q1.am->offset=idx;
cnt++;
}
if((p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
p2->q2.am=am=mymalloc(sizeof(*am));
p2->q2.am->flags=REG_IND;
p2->q2.am->base=base;
p2->q2.am->offset=idx;
cnt++;
}
if((p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
p2->z.am=am=mymalloc(sizeof(*am));
p2->z.am->flags=REG_IND;
p2->z.am->base=base;
p2->z.am->offset=idx;
cnt++;
}
if(isreg(q1)){
p->code=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
}else{
p->code=ASSIGN;p->q2.flags=0;
}
if(cnt==1&&((p2->q1.flags&(DREFOBJ|REG))!=REG||p2->q1.reg!=base)
&&((p2->q2.flags&(DREFOBJ|REG))!=REG||p2->q2.reg!=base)
&&((p2->z.flags&(DREFOBJ|REG))!=REG||p2->z.reg!=base) ){
/* Can we use update? */
p2=p2->next;
while(p2&&(p2->code==FREEREG||p2->code==ALLOCREG)) p2=p2->next;
if(p2){
c2=p2->code;
if(c2==ADDI2P){
if((p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==base
&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==base
&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==idx){
am->flags|=UPDATE;
p2->code=NOP;
}
}
}
}
continue;
}
}
}
}
}
static void toc_entry(FILE *f,struct Var *v)
/* Create a toc-entry. */
{
if(!use_sd(v->vtyp->flags)||(v->tattr&1)){
if(v->storage_class==STATIC&&(v->vtyp->flags&NQ)!=FUNKT){
fprintf(f,"\t.tocd\n");
fprintf(f,"%s%s%ld:\n",tocprefix,labprefix,zl2l(v->offset));
fprintf(f,"\t.long\t%s%ld\n",labprefix,zl2l(v->offset));
}else{
if ((v->vtyp->flags&NQ)!=FUNKT){
fprintf(f,"\t.tocd\n");
fprintf(f,"%s%s%s:\n",tocprefix,idprefix,v->identifier);
fprintf(f,"\t.long\t%s%s\n",idprefix,v->identifier);
}
if(v->storage_class==EXTERN)
fprintf(f,"\t.global\t%s%s%s\n",tocprefix,idprefix,v->identifier);
}
section=TOC;
}
}
static int stmw,stme;
static void function_top(FILE *f,struct Var *v,long offset)
/* Generates function top. */
{
int i,preg;long of;
if(g_flags[12]&USEDFLAG) toc_entry(f,v);
if(mregnames[1]!=regnames[1]) fprintf(f,"#vsc elf\n");
if(g_flags[0]&USEDFLAG) fprintf(f,"#vsc cpu %s\n",g_flags_val[0].p);
if(g_flags[1]&USEDFLAG) fprintf(f,"#vsc fpu %s\n",g_flags_val[1].p);
if(section!=CODE){fprintf(f,codename);section=CODE;}
fprintf(f,"\t.sdreg\t%s\n",mregnames[sd]);
if(v->storage_class==EXTERN) fprintf(f,"\t.global\t%s%s\n",idprefix,v->identifier);
fprintf(f,"\t.align\t4\n%s%s:\n",idprefix,v->identifier);
frameoffset=minframe+maxpushed;
framesize=frameoffset+offset;
stmw=0;stme=0;
for(i=1;i<=64;i++){
if((i==sd&&(v->tattr&8))||(regused[i]&&!regscratch[i]&&!regsa[i])){
if(i<=32) framesize+=4; else framesize+=8;
if(stmw||(regnames[i][0]=='r'&®names[i][1]=='3'&®names[i][2]=='1'))
stmw=i;
}else{
if(stmw){ stme=stmw;stmw=0;}
}
}
if(!(g_flags[11]&USEDFLAG)) stme=0;
for(crsave=0,i=65;i<=72;i++)
if(regused[i]&&!regscratch[i]&&!regsa[i]) crsave=1;
if(crsave&&!(g_flags[12]&USEDFLAG)) framesize+=4;
if(framesize==minframe&&function_calls==0&&!crsave) framesize=frameoffset=0;
framesize=(framesize+15)/16*16;
if(function_calls){
if(g_flags[12]&USEDFLAG)
fprintf(f,"\tmflr\t%s\n\tst%s\t%s,8(%s)\n",mregnames[t1],sdt[LONG],mregnames[t1],mregnames[sp]);
else
fprintf(f,"\tmflr\t%s\n\tst%s\t%s,4(%s)\n",mregnames[t1],sdt[LONG],mregnames[t1],mregnames[sp]);
}
of=minframe+maxpushed+offset;
if(framesize!=0){
if(framesize<=32767){
fprintf(f,"\tstwu\t%s,-%ld(%s)\n",mregnames[sp],framesize,mregnames[sp]);
preg=sp;
}else{
fprintf(f,"\tmr\t%s,%s\n",mregnames[t2],mregnames[sp]);
fprintf(f,"\tlis\t%s,%ld\n",mregnames[t1],hi(-framesize));
fprintf(f,"\taddi\t%s,%s,%ld\n",mregnames[t1],mregnames[t1],lo(-framesize));
fprintf(f,"\tstwux\t%s,%s,%s\n",mregnames[sp],mregnames[sp],mregnames[t1]);
preg=t2;of-=framesize;
}
}
if(crsave){
if(g_flags[12]&USEDFLAG){
fprintf(f,"\tmfcr\t%s\n\tst%s\t%s,4(%s)\n",mregnames[t1],sdt[LONG],mregnames[t1],mregnames[preg]);
}else{
fprintf(f,"\tmfcr\t%s\n\tst%s\t%s,%ld(%s)\n",mregnames[t1],sdt[LONG],mregnames[t1],of,mregnames[preg]);
of+=4;
}
}
for(i=1;i<=64;i++){
if((i==sd&&(v->tattr&8))||(regused[i]&&!regscratch[i]&&!regsa[i])){
if(i<=32){
if(stme&&stme!=i&®names[i][1]=='3'&®names[i][2]=='1'){
fprintf(f,"\tstmw\t%s,%ld(%s)\n",mregnames[stme],of,mregnames[preg]);
of+=(stme-i+1)*4;
i=stme;
}else{
fprintf(f,"\tst%s\t%s,%ld(%s)\n",sdt[LONG],mregnames[i],of,mregnames[preg]);
of+=4;
}
}else{
fprintf(f,"\tst%s\t%s,%ld(%s)\n",sdt[DOUBLE],mregnames[i],of,mregnames[preg]);
of+=8;
}
}
}
if(v->tattr&8){
if(g_flags[12]&USEDFLAG){
fprintf(f,"\t.global\t%s__getr2\n",idprefix);
if(!function_calls)
fprintf(f,"\tmflr\t%s\n",mregnames[t2]);
fprintf(f,"\tbl\t%s__getr2\n",idprefix);
if(!function_calls)
fprintf(f,"\tmtlr\t%s\n",mregnames[t2]);
}else{
fprintf(f,"\tlis\t%s,%s_LinkerDB@ha\n",mregnames[sd],idprefix);
fprintf(f,"\taddi\t%s,%s,%s_LinkerDB@l\n",mregnames[sd],mregnames[sd],idprefix);
}
}
}
static void function_bottom(FILE *f,struct Var *v,long offset)
/* Generates function bottom. */
{
int i,preg;long of;
of=minframe+maxpushed+offset;
if(framesize<=32767){
preg=sp;
}else{
fprintf(f,"\tlwz\t%s,0(%s)\n",mregnames[t2],mregnames[sp]);
preg=t2;of-=framesize;
}
if(crsave){
if(g_flags[12]&USEDFLAG){
fprintf(f,"\tl%s\t%s,8(%s)\n\tmtcr\t%s\n",ldt[LONG],mregnames[t1],mregnames[preg],mregnames[t1]);
}else{
fprintf(f,"\tl%s\t%s,%ld(%s)\n\tmtcr\t%s\n",ldt[LONG],mregnames[t1],of,mregnames[preg],mregnames[t1]);
of+=4;
}
}
for(i=1;i<=64;i++){
if((i==sd&&(v->tattr&8))||(regused[i]&&!regscratch[i]&&!regsa[i])){
if(i<=32){
if(stme&&stme!=i&®names[i][1]=='3'&®names[i][2]=='1'){
fprintf(f,"\tlmw\t%s,%ld(%s)\n",mregnames[stme],of,mregnames[preg]);
of+=(stme-i+1)*4;
i=stme;
}else{
fprintf(f,"\tl%s\t%s,%ld(%s)\n",ldt[LONG],mregnames[i],of,mregnames[preg]);
of+=4;
}
}else{
fprintf(f,"\tl%s\t%s,%ld(%s)\n",ldt[DOUBLE],mregnames[i],of,mregnames[preg]);
of+=8;
}
}
}
if(framesize){
if(framesize<=32767)
fprintf(f,"\taddi\t%s,%s,%ld\n",mregnames[sp],mregnames[sp],framesize);
else
fprintf(f,"\tmr\t%s,%s\n",mregnames[sp],mregnames[preg]);
}
if(function_calls){
if(g_flags[12]&USEDFLAG)
fprintf(f,"\tl%s\t%s,8(%s)\n\tmtlr\t%s\n",ldt[LONG],mregnames[t1],mregnames[sp],mregnames[t1]);
else
fprintf(f,"\tl%s\t%s,4(%s)\n\tmtlr\t%s\n",ldt[LONG],mregnames[t1],mregnames[sp],mregnames[t1]);
}
fprintf(f,"\tblr\n");
fprintf(f,"\t.type\t%s%s,@function\n",idprefix,v->identifier);
fprintf(f,"\t.size\t%s%s,$-%s%s\n",idprefix,v->identifier,idprefix,v->identifier);
}
static int is_const(struct Typ *t)
/* Tests if a type can be placed in the code-section. */
{
if(!(t->flags&(CONST|STRINGCONST))){
do{
if(t->flags&(CONST|STRINGCONST)) return 1;
if((t->flags&NQ)!=ARRAY) return 0;
t=t->next;
}while(1);
}else return 1;
}
static int balign(struct obj *o)
/* Liefert die unteren 2 Bits des Objekts. -1 wenn unklar. */
{
int sc;
if(o->flags&DREFOBJ) return -1;
if(o->am) ierror(0);
if(!(o->flags&VAR)) ierror(0);
sc=o->v->storage_class;
if(sc==EXTERN||sc==STATIC){
/* Alle statischen Daten werden vom cg auf 32bit alignt. */
return zl2l(zland(o->val.vlong,l2zl(3L)));
}
if(sc==AUTO||sc==REGISTER){
zlong of=o->v->offset;
if(!zlleq(l2zl(0L),of))
of=zlsub(l2zl(0L),zladd(of,maxalign));
return zl2l(zland(zladd(of,o->val.vlong),l2zl(3L)));
}
ierror(0);
}
/****************************************/
/* End of private data and functions. */
/****************************************/
int init_cg(void)
/* Does necessary initializations for the code-generator. Gets called */
/* once at the beginning and should return 0 in case of problems. */
{
int i;
/* Initialize some values which cannot be statically initialized */
/* because they are stored in the target's arithmetic. */
maxalign=l2zl(4L);
char_bit=l2zl(8L);
if(g_flags[7]&USEDFLAG){
malign[INT]=malign[LONG]=malign[POINTER]=malign[FLOAT]=malign[DOUBLE]=2;
}
for(i=0;i<16;i++){
sizetab[i]=l2zl(msizetab[i]);
align[i]=l2zl(malign[i]);
}
for(i=0;i<=MAXR;i++) mregnames[i]=regnames[i];
for(i= 1;i<=32;i++){
regsize[i]=l2zl(4L);
regtype[i]=<yp;
if(g_flags[8]&USEDFLAG) mregnames[i]++;
}
for(i=33;i<=64;i++){
regsize[i]=l2zl(8L);
regtype[i]=&ldbl;
if(g_flags[8]&USEDFLAG) mregnames[i]++;
}
for(i=65;i<=72;i++){
regsize[i]=l2zl(1L);
regtype[i]=&lchar;
if(g_flags[8]&USEDFLAG) mregnames[i]+=2;
}
/* Use multiple ccs. */
multiple_ccs=1;
/* Initialize the min/max-settings. Note that the types of the */
/* host system may be different from the target system and you may */
/* only use the smallest maximum values ANSI guarantees if you */
/* want to be portable. */
/* That's the reason for the subtraction in t_min[INT]. Long could */
/* be unable to represent -2147483648 on the host system. */
t_min[UNSIGNED|CHAR]=t_min[UNSIGNED|SHORT]=t_min[UNSIGNED|INT]=t_min[UNSIGNED|LONG]=l2zl(0L);
t_min[CHAR]=l2zl(-128L);
t_min[SHORT]=l2zl(-32768L);
t_min[INT]=zlsub(l2zl(-2147483647L),l2zl(1L));
t_min[LONG]=t_min[INT];
t_max[CHAR]=ul2zul(127UL);
t_max[SHORT]=ul2zul(32767UL);
t_max[INT]=ul2zul(2147483647UL);
t_max[LONG]=t_max[INT];
t_max[UNSIGNED|CHAR]=ul2zul(255UL);
t_max[UNSIGNED|SHORT]=ul2zul(65535UL);
t_max[UNSIGNED|INT]=ul2zul(4294967295UL);
t_max[UNSIGNED|LONG]=t_max[UNSIGNED|INT];
/* Reserve a few registers for use by the code-generator. */
/* This is not optimal but simple. */
if(g_flags[12]&USEDFLAG) sd=r2;
regsa[t1]=regsa[t2]=regsa[t3]=1;
regsa[f1]=regsa[f2]=regsa[f3]=1;
regsa[sp]=regsa[fp]=regsa[sd]=regsa[r2]=1;
regscratch[t1]=regscratch[t2]=regscratch[t3]=0;
regscratch[f1]=regscratch[f2]=regscratch[f3]=0;
regscratch[sp]=regscratch[fp]=regscratch[sd]=regscratch[r2]=0;
if(g_flags[6]&USEDFLAG) {minframe=8;labprefix=".l";idprefix="";}
if(g_flags[12]&USEDFLAG) {minframe=24;labprefix="l";idprefix="_";}
return 1;
}
int freturn(struct Typ *t)
/* Returns the register in which variables of type t are returned. */
/* If the value cannot be returned in a register returns 0. */
/* A pointer MUST be returned in a register. The code-generator */
/* has to simulate a pseudo register if necessary. */
{
if((t->flags&NQ)==FLOAT||(t->flags&NQ)==DOUBLE) return 46;
if((t->flags&NQ)==STRUCT||(t->flags&NQ)==UNION) return 0;
if(zlleq(szof(t),l2zl(4L))) return(r3); else return 0;
}
int regok(int r,int t,int mode)
/* Returns 0 if register r cannot store variables of */
/* type t. If t==POINTER and mode!=0 then it returns */
/* non-zero only if the register can store a pointer */
/* and dereference a pointer to mode. */
{
if(r==0) return 0;
t&=NQ;
if(t==0){
if(r>=65&&r<=72) return 1; else return 0;
}
if((t==FLOAT||t==DOUBLE)&&r>=33&&r<=64) return 1;
if(t==POINTER&&r>=1&&r<=32) return 1;
if(t>=CHAR&&t<=LONG&&r>=1&&r<=32) return 1;
return 0;
}
int dangerous_IC(struct IC *p)
/* Returns zero if the IC p can be safely executed */
/* without danger of exceptions or similar things. */
/* vbcc may generate code in which non-dangerous ICs */
/* are sometimes executed although control-flow may */
/* never reach them (mainly when moving computations */
/* out of loops). */
/* Typical ICs that generate exceptions on some */
/* machines are: */
/* - accesses via pointers */
/* - division/modulo */
/* - overflow on signed integer/floats */
{
int c=p->code;
if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
return 0;
if((c==DIV||c==MOD)&&!(p->q2.flags&KONST))
return 1;
return 0;
}
int must_convert(np p,int t)
/* Returns zero if code for converting np to type t */
/* can be omitted. */
/* On the PowerPC cpu pointers and 32bit */
/* integers have the same representation and can use */
/* the same registers. */
{
int o=p->ntyp->flags,op=o&NQ,tp=t&NQ;
if((op==INT||op==LONG||op==POINTER)&&(tp==INT||tp==LONG||tp==POINTER))
return 0;
return 1;
}
void gen_ds(FILE *f,zlong size,struct Typ *t)
/* This function has to create <size> bytes of storage */
/* initialized with zero. */
{
if(newobj&§ion!=TOC) fprintf(f,"%ld\n",zl2l(size));
else fprintf(f,"\t.space\t%ld\n",zl2l(size));
newobj=0;
}
void gen_align(FILE *f,zlong align)
/* This function has to make sure the next data is */
/* aligned to multiples of <align> bytes. */
{
fprintf(f,"\t.align\t2\n");
}
void gen_var_head(FILE *f,struct Var *v)
/* This function has to create the head of a variable */
/* definition, i.e. the label and information for */
/* linkage etc. */
{
int constflag;
if(v->clist) constflag=is_const(v->vtyp);
if(v->storage_class==STATIC){
if((v->vtyp->flags&NQ)==FUNKT) return;
if(use_sd(v->vtyp->flags)&&!(v->tattr&1)){
if(section!=TOC){fprintf(f,tocname);section=TOC;}
}else{
if(g_flags[12]&USEDFLAG) toc_entry(f,v);
if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&§ion!=DATA){fprintf(f,dataname);section=DATA;}
if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&§ion!=RODATA){fprintf(f,rodataname);section=RODATA;}
if(!v->clist&§ion!=BSS){fprintf(f,bssname);section=BSS;}
}
fprintf(f,"\t.type\t%s%ld,@object\n",labprefix,zl2l(v->offset));
fprintf(f,"\t.size\t%s%ld,%ld\n",labprefix,zl2l(v->offset),zl2l(szof(v->vtyp)));
if(v->clist||section==TOC)
fprintf(f,"%s%ld:\n",labprefix,zl2l(v->offset));
else
fprintf(f,"\t.lcomm\t%s%ld,",labprefix,zl2l(v->offset));
newobj=1;
}
if(v->storage_class==EXTERN){
fprintf(f,"\t.global\t%s%s\n",idprefix,v->identifier);
if((g_flags[12]&USEDFLAG)&&(!use_sd(v->vtyp->flags)||(v->tattr&1)))
fprintf(f,"\t.global\t%s%s%s\n",tocprefix,idprefix,v->identifier);
if(v->flags&(DEFINED|TENTATIVE)){
if(use_sd(v->vtyp->flags)&&!(v->tattr&1)){
if(section!=TOC){fprintf(f,tocname);section=TOC;}
}else{
if(g_flags[12]&USEDFLAG) toc_entry(f,v);
if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&§ion!=DATA){fprintf(f,dataname);section=DATA;}
if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&§ion!=RODATA){fprintf(f,rodataname);section=RODATA;}
if(!v->clist&§ion!=BSS){fprintf(f,bssname);section=BSS;}
}
fprintf(f,"\t.type\t%s%s,@object\n",idprefix,v->identifier);
fprintf(f,"\t.size\t%s%s,%ld\n",idprefix,v->identifier,zl2l(szof(v->vtyp)));
if(v->clist||section==TOC)
fprintf(f,"%s%s:\n",idprefix,v->identifier);
else
fprintf(f,"\t.comm\t%s%s,",idprefix,v->identifier);
newobj=1;
}
}
}
void gen_dc(FILE *f,int t,struct const_list *p)
/* This function has to create static storage */
/* initialized with const-list p. */
{
if((t&NQ)==POINTER) t=UNSIGNED|LONG;
fprintf(f,"\t.%s\t",dct[t&NQ]);
if(!p->tree){
if((t&NQ)==FLOAT||(t&NQ)==DOUBLE){
/* auch wieder nicht sehr schoen und IEEE noetig */
unsigned char *ip;
ip=(unsigned char *)&p->val.vdouble;
fprintf(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
if((t&NQ)==DOUBLE){
fprintf(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
}
}else{
printval(f,&p->val,t&NU,0);
}
}else{
probj2(f,&p->tree->o,t&NU);
}
fprintf(f,"\n");newobj=0;
}
/* The main code-generation routine. */
/* f is the stream the code should be written to. */
/* p is a pointer to a doubly linked list of ICs */
/* containing the function body to generate code for. */
/* v is a pointer to the function. */
/* offset is the size of the stackframe the function */
/* needs for local variables. */
void gen_code(FILE *f,struct IC *p,struct Var *v,zlong offset)
/* The main code-generation. */
{
int c,t,i,addbuf,varargs=0,fixedgpr,fixedfpr,setcc,ccset;
char *fpp;int fpf;struct IC *m;
long of=(zl2l(offset)+3)/4*4,regbase,tmpoff;
if(DEBUG&1) printf("gen_code()\n");
for(c=1;c<=MAXR;c++) regs[c]=regsa[c];
maxpushed=0;addbuf=0;
for(m=p;m;m=m->next){
c=m->code;t=m->typf&NU;
if(c==ALLOCREG) {regs[m->q1.reg]=1;continue;}
if(c==FREEREG) {regs[m->q1.reg]=0;continue;}
if(c==COMPARE&&(m->q2.flags&KONST)){
eval_const(&m->q2.val,t);
if(zleqto(vlong,l2zl(0L))&&zdeqto(vdouble,d2zd(0.0))){
m->q2.flags=0;m->code=c=TEST;
}
}
if((t&NQ)<=LONG&&(m->q2.flags&KONST)&&(t&NQ)<=LONG&&(c==MULT||c==DIV||(c==MOD&&(t&UNSIGNED)))){
eval_const(&m->q2.val,t);
i=pof2(vlong);
if(i){
if(c==MOD){
vlong=zlsub(vlong,l2zl(1L));
m->code=AND;
}else{
vlong=l2zl(i-1);
if(c==DIV) m->code=RSHIFT; else m->code=LSHIFT;
}
c=m->code;
if((t&NU)==CHAR) m->q2.val.vchar=zl2zc(vlong);
else if((t&NU)==SHORT) m->q2.val.vshort=zl2zs(vlong);
else if((t&NU)==INT) m->q2.val.vint=zl2zi(vlong);
else if((t&NU)==LONG) m->q2.val.vlong=vlong;
vulong=zl2zul(vlong);
if((t&NU)==(UNSIGNED|CHAR)) m->q2.val.vuchar=zul2zuc(vulong);
else if((t&NU)==(UNSIGNED|SHORT)) m->q2.val.vushort=zul2zus(vulong);
else if((t&NU)==(UNSIGNED|INT)) m->q2.val.vuint=zul2zui(vulong);
else if((t&NU)==(UNSIGNED|LONG)) m->q2.val.vulong=vulong;
}
}
if((c==CONVFLOAT||c==CONVDOUBLE)&&t!=FLOAT&&t!=DOUBLE&&addbuf<8) addbuf=8;
if((t==FLOAT||t==DOUBLE)&&c>=CONVCHAR&&c<=CONVULONG&&addbuf<8) addbuf=8;
if(c==CALL&&maxpushed<zl2l(m->q2.val.vlong)) maxpushed=zl2l(m->q2.val.vlong);
if(c==CALL&&(m->q1.flags&VAR)&&!strcmp(m->q1.v->identifier,"__va_start")) varargs=1;
}
if(g_flags[9]&USEDFLAG) peephole(p);
if(varargs){
fixedgpr=fixedfpr=0;
for(i=0;i<v->vtyp->exact->count;i++){
c=(*v->vtyp->exact->sl)[i].styp->flags&NQ;
if(c==POINTER||c<=LONG) fixedgpr++;
if(c==FLOAT||c==DOUBLE) fixedfpr++;
}
regbase=of; /* merken */
addbuf+=96;
}
of+=addbuf;tmpoff=minframe+maxpushed+of;
function_top(f,v,of);
if(varargs){
regbase=frameoffset+regbase;
fpp="";
if(!(g_flags[8]&USEDFLAG)) fpp="r";
for(i=fixedgpr;i<8;i++)
fprintf(f,"\tstw\t%s%d,%ld(%s)\n",fpp,i+3,regbase+i*4,mregnames[sp]);
if(!(g_flags[8]&USEDFLAG)) fpp="f";
for(i=fixedfpr;i<8;i++)
fprintf(f,"\tstfd\t%s%d,%ld(%s)\n",fpp,i+1,regbase+32+i*8,mregnames[sp]);
}
pushed=0;ccset=0;
for(;p;pr(f,p),p=p->next){
c=p->code;t=p->typf;
if(c<0) {setcc=1;c=-c;} else setcc=0;
if(c==NOP) {p->z.flags=0;continue;}
if(c==ALLOCREG) {regs[p->q1.reg]=1;continue;}
if(c==FREEREG) {regs[p->q1.reg]=0;continue;}
if(c==LABEL) {ccset=0;fprintf(f,"%s%d:\n",labprefix,t);continue;}
if(c==BRA) {ccset=0;fprintf(f,"\tb\t%s%d\n",labprefix,t);continue;}
if(c>=BEQ&&c<BRA){
ccset=0;
if(!(p->q1.flags®)) p->q1.reg=cr0;
if((g_flags[9]&USEDFLAG)&&!BTST(twice,p->typf-lastlabel)){
struct IC *p2,*p3,*p4;int exit_label;
p2=p->next;
while(p2&&(p2->code==FREEREG||p2->code==ALLOCREG)) p2=p2->next;
if(p2&&p2->code==SETRETURN&&p2->z.reg){p2->code=ASSIGN;p2->z.flags=REG;}
if(p2&&p2->code==ASSIGN&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg<=32){
p3=p2->next;
while(p3&&(p3->code==FREEREG||p3->code==ALLOCREG)) p3=p3->next;
if(p3&&p3->code==BRA){
exit_label=p3->typf;
p3=p3->next;
while(p3&&(p3->code==FREEREG||p3->code==ALLOCREG)) p3=p3->next;
if(p3&&p3->code==LABEL&&p3->typf==p->typf){
p3=p3->next;
while(p3&&(p3->code==FREEREG||p3->code==ALLOCREG)) p3=p3->next;
if(p3&&p3->code==SETRETURN&&p3->z.reg){p3->code=ASSIGN;p3->z.flags=REG;}
if(p3&&p3->code==ASSIGN&&(p3->z.flags&(REG|DREFOBJ))==REG&&p3->z.reg==p2->z.reg){
p4=p3->next;
while(p4&&(p4->code==FREEREG||p4->code==ALLOCREG)) p4=p4->next;
if(p4&&p4->code==LABEL&&p4->typf==exit_label){
int bit=(p->q1.reg-cr0)*4;
if((p2->q1.flags&KONST)&&(p3->q1.flags&KONST)){
eval_const(&p2->q1.val,p2->typf);
if(zleqto(vlong,l2zl(0L))){
eval_const(&p3->q1.val,p3->typf);
if(zleqto(vlong,l2zl(1L))||zleqto(vlong,l2zl(-1L))){
if(c==BLE){fprintf(f,"\tcror\t%d,%d,%d\n",bit,bit,bit+2);}
if(c==BGE){bit++;fprintf(f,"\tcror\t%d,%d,%d\n",bit,bit,bit+1);}
if(c==BNE){bit+=2;fprintf(f,"\tcrnor\t%d,%d,%d\n",bit,bit,bit);}
if(c==BGT) bit++;
if(c==BEQ) bit+=2;
fprintf(f,"\tmfcr\t%s\n",mregnames[t1]);
fprintf(f,"\trlwinm\t%s,%s,%d,%d,%d\n",mregnames[p2->z.reg],mregnames[t1],bit+1,31,31);
if(zleqto(vlong,l2zl(-1L))) fprintf(f,"\tneg\t%s,%s\n",mregnames[p2->z.reg],mregnames[p2->z.reg]);
if(BTST(twice,p4->typf-lastlabel)) fprintf(f,"%s%d:\n",labprefix,p4->typf);
p=p4;continue;
}
}else{
eval_const(&p3->q1.val,p3->typf);
if(zleqto(vlong,l2zl(0L))){
eval_const(&p2->q1.val,p2->typf);
if(zleqto(vlong,l2zl(1L))||zleqto(vlong,l2zl(-1L))){
if(c==BLE){fprintf(f,"\tcrnor\t%d,%d,%d\n",bit,bit,bit+2);}
if(c==BGE){bit++;fprintf(f,"\tcrnor\t%d,%d,%d\n",bit,bit,bit+1);}
if(c==BNE){bit+=2;}
if(c==BGT){bit++;fprintf(f,"\tcrnor\t%d,%d,%d\n",bit,bit,bit);}
if(c==BEQ){bit+=2;fprintf(f,"\tcrnor\t%d,%d,%d\n",bit,bit,bit);}
if(c==BLT){fprintf(f,"\tcrnor\t%d,%d,%d\n",bit,bit,bit);}
fprintf(f,"\tmfcr\t%s\n",mregnames[t1]);
fprintf(f,"\trlwinm\t%s,%s,%d,%d,%d\n",mregnames[p2->z.reg],mregnames[t1],bit+1,31,31);
if(zleqto(vlong,l2zl(-1L))) fprintf(f,"\tneg\t%s,%s\n",mregnames[p2->z.reg],mregnames[p2->z.reg]);
if(BTST(twice,p4->typf-lastlabel)) fprintf(f,"%s%d:\n",labprefix,p4->typf);
p=p4;continue;
}
}
}
}
}
}
}
}
}
}
fprintf(f,"\tb%s\t%s,%s%d\n",ccs[c-BEQ],mregnames[p->q1.reg],labprefix,t);
continue;
}
if(c==MOVETOREG){
if(p->z.reg<=32){
load_reg(f,p->z.reg,&p->q1,INT,0);
}else{
if(p->z.reg>64) ierror(0);
load_reg(f,p->z.reg,&p->q1,DOUBLE,0);
}
p->z.flags=0;
continue;
}
if(c==MOVEFROMREG){
if(p->q1.reg<=32){
store_reg(f,p->q1.reg,&p->z,INT);
}else{
if(p->q1.reg>64) ierror(0);
store_reg(f,p->q1.reg,&p->z,DOUBLE);
}
p->z.flags=0;
continue;
}
if((c==ASSIGN||c==PUSH)&&((t&NQ)>POINTER||((t&NQ)==CHAR&&zl2l(p->q2.val.vlong)!=1))){
unsigned long size,l;
int a1,a2,b;char *ld,*st;
size=zl2l(p->q2.val.vlong);
a1=balign(&p->q1);
if(c==ASSIGN) a2=balign(&p->z); else a2=0;
b=1;ld=ldt[CHAR];st=sdt[CHAR];
if(a1>=0&&a2>=0){
if(a1==0&&a2==0){
b=4;ld=ldt[INT];st=sdt[INT];
}else if((a1&1)==0&&(a2&1)==0){
b=2;ld=ldt[SHORT];st=sdt[SHORT];
}
}
if(p->q1.flags&DREFOBJ){
if(p->q1.am){
if(p->q1.am->flags®_IND) fprintf(f,"\tadd\t%s,%s,%s\n",mregnames[t1],mregnames[p->q1.am->offset],mregnames[p->q1.am->base]);
if(p->q1.am->flags&IMM_IND) fprintf(f,"\taddi\t%s,%s,%ld\n",mregnames[t1],mregnames[p->q1.am->base],p->q1.am->offset);
}else{
p->q1.flags&=~DREFOBJ;
load_reg(f,t1,&p->q1,POINTER,t1);
p->q1.flags|=DREFOBJ;
}
}else{
load_address(f,t1,&p->q1,POINTER);
}
if(p->z.flags&DREFOBJ){
if(p->z.am){
if(p->z.am->flags®_IND) fprintf(f,"\tadd\t%s,%s,%s\n",mregnames[t2],mregnames[p->z.am->offset],mregnames[p->z.am->base]);
if(p->z.am->flags&IMM_IND) fprintf(f,"\taddi\t%s,%s,%ld\n",mregnames[t2],mregnames[p->z.am->base],p->z.am->offset);
}else{
p->z.flags&=~DREFOBJ;
load_reg(f,t2,&p->z,POINTER,t2);
p->z.flags|=DREFOBJ;
}
}else{
if(c==PUSH){
pushed=(pushed+3)/4*4;
fprintf(f,"\taddi\t%s,%s,%ld\n",mregnames[t2],mregnames[sp],pushed+minframe-b);
pushed+=size;
}else{
load_address(f,t2,&p->z,POINTER);
}
}
fprintf(f,"\taddi\t%s,%s,-%d\n",mregnames[t1],mregnames[t1],b);
if(c==ASSIGN) fprintf(f,"\taddi\t%s,%s,-%d\n",mregnames[t2],mregnames[t2],b);
l=size/(8*b);
if(l>1){
if(hi(l)) fprintf(f,"\tlis\t%s,%ld\n",mregnames[t3],hi(l));
fprintf(f,"\tli\t%s,%ld\n",mregnames[t3],lo(l));
fprintf(f,"\tmtctr\t%s\n",mregnames[t3]);
fprintf(f,"%s%d:\n",labprefix,++label);
}
if(l>0){
for(i=b;i<=7*b;i+=b){
fprintf(f,"\tl%s\t%s,%d(%s)\n",ld,mregnames[t3],i,mregnames[t1]);
fprintf(f,"\tst%s\t%s,%d(%s)\n",st,mregnames[t3],i,mregnames[t2]);
}
fprintf(f,"\tl%su\t%s,%d(%s)\n",ld,mregnames[t3],i,mregnames[t1]);
fprintf(f,"\tst%su\t%s,%d(%s)\n",st,mregnames[t3],i,mregnames[t2]);
}
if(l>1){
fprintf(f,"\tbdnz\t%s%d\n",labprefix,label);
}
size=size%(8*b);
for(i=0;i<size/b;i++){
fprintf(f,"\tl%su\t%s,%d(%s)\n",ld,mregnames[t3],b,mregnames[t1]);
fprintf(f,"\tst%su\t%s,%d(%s)\n",st,mregnames[t3],b,mregnames[t2]);
}
size=size%b;i=b;
if(size&2){
fprintf(f,"\tl%su\t%s,%d(%s)\n",ldt[SHORT],mregnames[t3],b,mregnames[t1]);
fprintf(f,"\tst%su\t%s,%d(%s)\n",sdt[SHORT],mregnames[t3],b,mregnames[t2]);
i=2;
}
if(size&1){
fprintf(f,"\tl%su\t%s,%d(%s)\n",ldt[CHAR],mregnames[t3],i,mregnames[t1]);
fprintf(f,"\tst%su\t%s,%d(%s)\n",sdt[CHAR],mregnames[t3],i,mregnames[t2]);
}
p->z.flags=0;
continue;
}
if(c==TEST&&((t&NQ)==FLOAT||(t&NQ)==DOUBLE)){
p->code=c=COMPARE;
p->q2.flags=KONST;
p->q2.val.vdouble=d2zd(0.0);
if((t&NQ)==FLOAT) p->q2.val.vfloat=zd2zf(p->q2.val.vdouble);
}
p=do_refs(f,p);
c=p->code;
if(c<0) {setcc=1;c=-c;} else setcc=0;
if(c==SUBPFP) c=SUB;
if(c==ADDI2P) c=ADD;
if(c==SUBIFP) c=SUB;
if(c>=CONVCHAR&&c<=CONVULONG){
int to;
static struct obj o;char *ip;
long moff;int offreg;
if(c==CONVCHAR) to=CHAR;
if(c==CONVUCHAR) to=UNSIGNED|CHAR;
if(c==CONVSHORT) to=SHORT;
if(c==CONVUSHORT) to=UNSIGNED|SHORT;
if(c==CONVINT) to=LONG;
if(c==CONVUINT) to=UNSIGNED|LONG;
if(c==CONVLONG) to=LONG;
if(c==CONVULONG) to=UNSIGNED|LONG;
if(c==CONVFLOAT) to=FLOAT;
if(c==CONVDOUBLE) to=DOUBLE;
if(c==CONVPOINTER) to=UNSIGNED|LONG;
if(to==FLOAT||to==DOUBLE){
if((t&NQ)==FLOAT||(t&NQ)==DOUBLE){
zreg=q1reg;
continue;
}
if(tmpoff>32767){
moff=0;offreg=t1;
fprintf(f,"\taddis\t%s,%s,%ld\n",mregnames[offreg],mregnames[sp],hi(tmpoff));
fprintf(f,"\taddi\t%s,%s,%ld\n",mregnames[offreg],mregnames[offreg],lo(tmpoff));
}else{
moff=tmpoff;
offreg=sp;
}
if((t&NU)==(UNSIGNED|INT)||(t&NU)==(UNSIGNED|LONG)){
o.flags=KONST;
ip=(char *)&o.val.vdouble;
ip[0]=0x41;
ip[1]=0xe0;
ip[2]=0x00;
ip[3]=0x00;
ip[4]=0x00;
ip[5]=0x00;
ip[6]=0x00;
ip[7]=0x00;
load_reg(f,f2,&o,DOUBLE,t2);
fprintf(f,"\tfcmpu\t%s,%s,%s\n",mregnames[cr0],mregnames[q1reg],mregnames[f2]);
fprintf(f,"\tcror\t3,2,1\n");
fprintf(f,"\tbso\t%s,%s%d\n",mregnames[cr0],labprefix,++label);
fprintf(f,"\tfctiwz\t%s,%s\n",mregnames[f2],mregnames[q1reg]);
fprintf(f,"\tst%s\t%s,%ld(%s)\n",sdt[DOUBLE],mregnames[f2],moff-8,mregnames[offreg]);
fprintf(f,"\tl%s\t%s,%ld(%s)\n",ldt[t&NQ],mregnames[zreg],moff-zl2l(sizetab[t&NQ]),mregnames[offreg]);
fprintf(f,"\tb\t%s%d\n",labprefix,++label);
fprintf(f,"%s%d:\n",labprefix,label-1);
fprintf(f,"\tfsub\t%s,%s,%s\n",mregnames[f2],mregnames[q1reg],mregnames[f2]);
fprintf(f,"\tfctiwz\t%s,%s\n",mregnames[f2],mregnames[f2]);
fprintf(f,"\tst%s\t%s,%ld(%s)\n",sdt[DOUBLE],mregnames[f2],moff-8,mregnames[offreg]);
fprintf(f,"\tl%s\t%s,%ld(%s)\n",ldt[INT],mregnames[zreg],moff-zl2l(sizetab[t&NQ]),mregnames[offreg]);
fprintf(f,"\txoris\t%s,%s,32768\n",mregnames[zreg],mregnames[zreg]);
fprintf(f,"%s%d:\n",labprefix,label);
}else{
fprintf(f,"\tfctiwz\t%s,%s\n",mregnames[f3],mregnames[q1reg]);
fprintf(f,"\tst%s\t%s,%ld(%s)\n",sdt[DOUBLE],mregnames[f3],moff-8,mregnames[offreg]);
fprintf(f,"\tl%s\t%s,%ld(%s)\n",ldt[t&NQ],mregnames[zreg],moff-zl2l(sizetab[t&NQ]),mregnames[offreg]);
}
if(t==CHAR) fprintf(f,"\textsb\t%s,%s\n",mregnames[zreg],mregnames[zreg]);
continue;
}
if((t&NQ)==FLOAT||(t&NQ)==DOUBLE){
if(tmpoff>32767){
moff=0;offreg=t1;
fprintf(f,"\taddis\t%s,%s,%ld\n",mregnames[offreg],mregnames[sp],hi(tmpoff));
fprintf(f,"\taddi\t%s,%s,%ld\n",mregnames[offreg],mregnames[offreg],lo(tmpoff));
}else{
moff=tmpoff;
offreg=sp;
}
o.flags=KONST;
ip=(char *)&o.val.vdouble;
ip[0]=0x43;
ip[1]=0x30;
ip[2]=0x00;
ip[3]=0x00;
ip[4]=0x80;
ip[5]=0x00;
ip[6]=0x00;
ip[7]=0x00;
if((to&NU)==(UNSIGNED|INT)||(to&NU)==(UNSIGNED|LONG)){
ip[4]=0x00;
load_reg(f,f2,&o,DOUBLE,t2);
fprintf(f,"\tlis\t%s,17200\n",mregnames[t2]);
fprintf(f,"\tst%s\t%s,%ld(%s)\n",sdt[INT],mregnames[q1reg],moff-4,mregnames[offreg]);
fprintf(f,"\tst%s\t%s,%ld(%s)\n",sdt[INT],mregnames[t2],moff-8,mregnames[offreg]);
fprintf(f,"\tl%s\t%s,%ld(%s)\n",ldt[DOUBLE],mregnames[zreg],moff-8,mregnames[offreg]);
fprintf(f,"\tfsub\t%s,%s,%s\n",mregnames[zreg],mregnames[zreg],mregnames[f2]);
}else{
fprintf(f,"\tlis\t%s,17200\n",mregnames[t2]);
fprintf(f,"\tst%s\t%s,%ld(%s)\n",sdt[INT],mregnames[t2],moff-8,mregnames[offreg]);
fprintf(f,"\txoris\t%s,%s,32768\n",mregnames[t2],mregnames[q1reg]);
fprintf(f,"\tst%s\t%s,%ld(%s)\n",sdt[INT],mregnames[t2],moff-4,mregnames[offreg]);
fprintf(f,"\tl%s\t%s,%ld(%s)\n",ldt[DOUBLE],mregnames[zreg],moff-8,mregnames[offreg]);
load_reg(f,f2,&o,DOUBLE,t2);
fprintf(f,"\tfsub\t%s,%s,%s\n",mregnames[zreg],mregnames[zreg],mregnames[f2]);
}
continue;
}
if((t&NQ)>=(to&NQ)){
if((t&UNSIGNED)==(to&UNSIGNED)){
if(setcc){
fprintf(f,"\tmr.\t%s,%s\n",mregnames[zreg],mregnames[q1reg]);
ccset=1;
}else{
zreg=q1reg;
}
continue;
}else{
if((t&NU)==CHAR){
fprintf(f,"\textsb%s\t%s,%s\n",record[setcc],mregnames[zreg],mregnames[q1reg]);
ccset|=setcc;
}else if((t&NU)==SHORT){
fprintf(f,"\textsh%s\t%s,%s\n",record[setcc],mregnames[zreg],mregnames[q1reg]);
ccset|=setcc;
}else if((t&NU)==(UNSIGNED|CHAR)){
fprintf(f,"\tandi.\t%s,%s,255\n",mregnames[zreg],mregnames[q1reg]);
ccset=setcc;
}else if((t&NU)==(UNSIGNED|SHORT)){
fprintf(f,"\tandi.\t%s,%s,65535\n",mregnames[zreg],mregnames[q1reg]);
ccset=setcc;
}else{
if(setcc){
fprintf(f,"\tmr.\t%s,%s\n",mregnames[zreg],mregnames[q1reg]);
ccset=1;
}else{
zreg=q1reg;
}
}
continue;
}
}else{
if((t&NU)==CHAR){
fprintf(f,"\textsb%s\t%s,%s\n",record[setcc],mregnames[zreg],mregnames[q1reg]);
ccset|=setcc;
}else if((t&NU)==SHORT){
fprintf(f,"\textsh%s\t%s,%s\n",record[setcc],mregnames[zreg],mregnames[q1reg]);
ccset|=setcc;
}else if((t&NU)==(UNSIGNED|CHAR)){
fprintf(f,"\tandi.\t%s,%s,255\n",mregnames[zreg],mregnames[q1reg]);
ccset=setcc;
}else if((t&NU)==(UNSIGNED|SHORT)){
fprintf(f,"\tandi.\t%s,%s,65535\n",mregnames[zreg],mregnames[q1reg]);
ccset=setcc;
}else{
if(setcc){
fprintf(f,"\tmr.\t%s,%s\n",mregnames[zreg],mregnames[q1reg]);
ccset=1;
}else{
zreg=q1reg;
}
}
continue;
}
}
if(c==KOMPLEMENT){
fprintf(f,"\tnor%s\t%s,%s,%s\n",record[setcc],mregnames[zreg],mregnames[q1reg],mregnames[q1reg]);
ccset|=setcc;
continue;
}
if(c==SETRETURN){
if(p->z.reg){
if(zreg==0) load_reg(f,p->z.reg,&p->q1,t,t3);
}else
ierror(0);
continue;
}
if(c==GETRETURN){
if(p->q1.reg)
zreg=p->q1.reg;
else
p->z.flags=0;
continue;
}
if(c==CALL){
int reg;
ccset=0;
if((p->q1.flags&VAR)&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
fprintf(f,"%s\n",p->q1.v->fi->inline_asm);
}else{
if(p->q1.flags&VAR){
if(!strcmp("__va_start",p->q1.v->identifier)){
fprintf(f,"\taddi\t%s,%s,%ld\n",mregnames[r3],mregnames[sp],framesize+minframe);
continue;
}
if(!strcmp("__va_regbase",p->q1.v->identifier)){
fprintf(f,"\taddi\t%s,%s,%ld\n",mregnames[r3],mregnames[sp],regbase);
continue;
}
if(!strcmp("__va_fixedgpr",p->q1.v->identifier)){
fprintf(f,"\tli\t%s,%d\n",mregnames[r3],fixedgpr);
continue;
}
if(!strcmp("__va_fixedfpr",p->q1.v->identifier)){
fprintf(f,"\tli\t%s,%d\n",mregnames[r3],fixedfpr);
continue;
}
}
if(g_flags[10]&USEDFLAG) fprintf(f,"\tcreqv\t6,6,6\n");
if(q1reg){
fprintf(f,"\tmtlr\t%s\n",mregnames[q1reg]);
fprintf(f,"\tblrl\n");
}else{
fprintf(f,"\tbl\t");probj2(f,&p->q1,t);
fprintf(f,"\n");
}
}
pushed-=zl2l(p->q2.val.vlong);
continue;
}
if((t&NQ)==FLOAT||(t&NQ)==DOUBLE) {fpp="f";fpf=1;} else {fpp="";fpf=0;}
if(c==ASSIGN||c==PUSH){
if(t==0) ierror(0);
if(q1reg||c==PUSH){
if(c==PUSH){
if(zleqto(align[t&NQ],l2zl(8L))) pushed=(pushed+7)/8*8;
if(q1reg)
fprintf(f,"\tst%s\t%s,%ld(%s)\n",sdt[t&NQ],mregnames[q1reg],pushed+minframe,mregnames[sp]);
pushed+=zl2l(p->q2.val.vlong);
continue;
}
if(c==ASSIGN){
if(setcc&&!fpf){
fprintf(f,"\tmr.\t%s,%s\n",mregnames[zreg],mregnames[q1reg]);
ccset=1;
}else{
zreg=q1reg;
}
}
continue;
}
}
if(c==ADDRESS){
load_address(f,zreg,&p->q1,POINTER);
continue;
}
if(c==MINUS){
fprintf(f,"\t%sneg%s\t%s,%s\n",fpp,record[setcc&&!fpf],mregnames[zreg],mregnames[q1reg]);
if(setcc&&!fpf) ccset=1;
continue;
}
if(c==TEST){
if(!(p->z.flags®))
p->z.reg=cr0;
if(!multiple_ccs&&(t&UNSIGNED)){
struct IC *p2=p->next;
while(p2&&(p2->code==FREEREG||p2->code==ALLOCREG)) p2=p2->next;
if(!p2) ierror(0);
if(p2->code==BGT) p2->code=BNE;
else if(p2->code==BGE) p2->code=BRA;
else if(p2->code==BLT) p2->code=NOP;
else if(p2->code==BLE) p2->code=BEQ;
}
if(ccset&&p->z.reg==cr0) continue;
if((t&NQ)==FLOAT||(t&NQ)==DOUBLE)
ierror(0);
else
fprintf(f,"\tcmp%swi\t%s,%s,0\n",(t&UNSIGNED)?"l":"",mregnames[p->z.reg],mregnames[q1reg]);
if(p->z.reg==cr0) ccset=0;
continue;
}
if(c==COMPARE){
if(!(p->z.flags®))
p->z.reg=cr0;
if((t&NQ)==FLOAT||(t&NQ)==DOUBLE)
fprintf(f,"\tfcmpu\t%s,%s,",mregnames[p->z.reg],mregnames[q1reg]);
else
fprintf(f,"\tcmp%sw%s\t%s,%s,",(t&UNSIGNED)?"l":"",isimm[q2reg==0],mregnames[p->z.reg],mregnames[q1reg]);
probj2(f,&p->q2,t);fprintf(f,"\n");
if(p->z.reg==cr0) ccset=0;
continue;
}
if(c==AND&&q2reg==0){
ccset=setcc;
fprintf(f,"\tandi.\t%s,%s,",mregnames[zreg],mregnames[q1reg]);
probj2(f,&p->q2,t|UNSIGNED);fprintf(f,"\n");
continue;
}
if(c>=OR&&c<=AND){
fprintf(f,"\t%s%s%s\t%s,%s,",logicals[c-OR],isimm[q2reg==0],record[setcc&&q2reg],mregnames[zreg],mregnames[q1reg]);
probj2(f,&p->q2,t|UNSIGNED);fprintf(f,"\n");
if(setcc&&q2reg) ccset=1;
continue;
}
if(c==SUB&&(p->q1.flags&KONST)){
fprintf(f,"\tsubfic\t%s,%s,",mregnames[zreg],mregnames[q2reg]);
probj2(f,&p->q1,t&NQ);fprintf(f,"\n");
continue;
}
if(c>=LSHIFT&&c<=MOD){
if(c==RSHIFT&&!(t&UNSIGNED)){
fprintf(f,"\tsraw%s%s\t%s,%s,",isimm[q2reg==0],record[setcc],mregnames[zreg],mregnames[q1reg]);
probj2(f,&p->q2,t); fprintf(f,"\n");
ccset|=setcc;
continue;
}
if(c==MOD){
i=0;
if(zreg==q1reg||zreg==q2reg){
if(t1!=q1reg&&t1!=q2reg) i=t1;
if(t2!=q1reg&&t2!=q2reg) i=t2;
}else i=zreg;
if(i==0||i==q1reg||i==q2reg) ierror(0);
fprintf(f,"\tdivw%s\t%s,%s,%s\n",(t&UNSIGNED)?"u":"",mregnames[i],mregnames[q1reg],mregnames[q2reg]);
fprintf(f,"\tmullw\t%s,%s,%s\n",mregnames[i],mregnames[i],mregnames[q2reg]);
fprintf(f,"\tsubf%s\t%s,%s,%s\n",record[setcc],mregnames[zreg],mregnames[i],mregnames[q1reg]);
ccset|=setcc;
continue;
}
if(c==DIV&&(t&UNSIGNED)){
fprintf(f,"\tdivwu%s%s\t%s,%s,",isimm[q2reg==0],record[setcc&&q2reg],mregnames[zreg],mregnames[q1reg]);
if(setcc&&q2reg) ccset=1;
}else if(c==MULT&&((t&NQ)==FLOAT||(t&NQ)==DOUBLE)){
fprintf(f,"\tfmul\t%s,%s,",mregnames[zreg],mregnames[q1reg]);
}else if(c==DIV&&((t&NQ)==FLOAT||(t&NQ)==DOUBLE)){
fprintf(f,"\tfdiv\t%s,%s,",mregnames[zreg],mregnames[q1reg]);
}else if(c==MULT&&q2reg==0){
fprintf(f,"\tmulli\t%s,%s,",mregnames[zreg],mregnames[q1reg]);
}else if(c==ADD&&setcc&&!q2reg){
fprintf(f,"\taddic.\t%s,%s,",mregnames[zreg],mregnames[q1reg]);
ccset=1;
}else{
fprintf(f,"\t%s%s%s%s\t%s,%s,",fpp,arithmetics[c-LSHIFT],isimm[q2reg==0],record[setcc&&q2reg&&!fpf],mregnames[zreg],mregnames[q1reg]);
if(setcc&&q2reg&&!fpf) ccset=1;
}
probj2(f,&p->q2,t&NQ);fprintf(f,"\n");
continue;
}
ierror(0);
}
lastlabel=label;
free(once);free(twice);
function_bottom(f,v,of);
}
int shortcut(int code,int typ)
{
return 0;
}
int reg_parm(struct reg_handle *m, struct Typ *t,int vararg)
{
int f;
if(!m) ierror(0);
if(!t) ierror(0);
if(vararg&&(g_flags[12]&USEDFLAG)) return 0;
f=t->flags&NQ;
if(f<=LONG||f==POINTER){
if(m->gregs>=8) return 0;
if(g_flags[12]&USEDFLAG){
if(!(g_flags[13]&USEDFLAG)) m->fregs++;
return -(r3-m->gregs++);
}else{
return r3-m->gregs++;
}
}
if(f==FLOAT||f==DOUBLE){
if(g_flags[12]&USEDFLAG){
if(m->fregs>=13) return(0);
if(!(g_flags[13]&USEDFLAG)){
if(f==DOUBLE) m->gregs+=2; else m->gregs++;
}
return -(46-m->fregs++);
}else{
if(m->fregs>=8) return(0);
return 46-m->fregs++;
}
}
return 0;
}
void cleanup_cg(FILE *f)
{
struct fpconstlist *p;
unsigned char *ip;
struct StatFPtrList *tfp,*fp=firstfptr;
while(tfp=fp){
fp=fp->next;
free(tfp);
}
while(p=firstfpc){
if(f){
if((g_flags[12]&USEDFLAG)&&!use_sd(p->typ)){
fprintf(f,"\t.tocd\n");
fprintf(f,"%s%s%ld:\n",tocprefix,labprefix,zl2l(p->label));
fprintf(f,"\t.long\t%s%ld\n",labprefix,zl2l(p->label));
section=TOC;
}
if(use_sd(p->typ)){
if(section!=TOC){fprintf(f,tocname);section=TOC;}
}else{
if(section!=RODATA){fprintf(f,rodataname);section=RODATA;}
}
if((p->typ&NQ)==DOUBLE)
fprintf(f,"\t.align\t3\n");
else
fprintf(f,"\t.align\t2\n");
fprintf(f,"%s%d:\n\t.long\t",labprefix,p->label);
ip=(unsigned char *)&p->val.vdouble;
fprintf(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
if((p->typ&NQ)==DOUBLE){
fprintf(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
}
fprintf(f,"\n");
}
firstfpc=p->next;
free(p);
}
}